import { useCallback, useReducer } from "react";

const UNDO = "UNDO";
const REDO = "REDO";
const SET = "SET";
const RESET = "RESET";

interface State<T> {
  past: T[]
  present: T
  future: T[]
}

interface Action<T> {
  newPresent?: T,
  type: typeof UNDO | typeof REDO | typeof SET | typeof RESET
}

const undoReducer = <T> (state: State<T>, action: Action<T>) => {
  const { past, present, future } = state;
  const { type, newPresent } = action;
  switch (type) {
    case UNDO: {
      if (past.length === 0) return state;
      const previous = past[past.length - 1];
      const newPast = past.slice(0, past.length - 1);

      return {
        past: newPast,
        present: previous,
        future: [present, ...future]
      };
    }
    case REDO: {
      if (future.length === 0) return state;

      const next = future[0];
      const newFuture = future.slice(1, past.length);

      return {
        past: [...past, present],
        present: next,
        future: newFuture
      };
    }
    case SET: {
      if (newPresent === present) return state;
      return {
        past: [...past, newPresent],
        present: newPresent,
        future: []
      };
    }
    case RESET: {
      return {
        past: [],
        present: newPresent,
        future: []
      };
    }
  }
};

export const useUndo = <T> (initialPresent: T) => {
  const [state, dispatch] = useReducer(undoReducer, {
    past: [],
    present: initialPresent,
    future: []
  } as State<T>);

  const canUndo = state.past.length !== 0;
  const canRedo = state.future.length !== 0;

  const undo = useCallback(() => dispatch({ type: UNDO }), []);

  const redo = useCallback(() => dispatch({ type: REDO }), []);

  const set = useCallback((newPresent) => dispatch({ type: SET, newPresent }), []);

  const reset = useCallback((newPresent) => dispatch({ type: RESET, newPresent }), []);

  return {
    undo, redo, set, reset,
    canUndo, canRedo
  };
};


// export const useUndo = <T> (initialPresent: T) => {
//   // const [past, setPast] = useState<T[]>([])
//   // const [present, setPresent] = useState(initialPresent)
//   // const [future, setFuture] = useState<T[]>([])
//
//   // 组合状态
//   const [state, setState] = useState<{
//     past: T[],
//     present: T,
//     future: T[]
//   }>({
//     past: [],
//     present: initialPresent,
//     future: []
//   });
//
//   const canUndo = state.past.length !== 0;
//   const canRedo = state.future.length !== 0;
//
//   const undo = useCallback(() => {
//     setState(currentState => {
//       const { past, present, future } = currentState;
//       if (past.length === 0) return currentState;
//
//       const previous = past[past.length - 1];
//       const newPast = past.slice(0, past.length - 1);
//
//       return {
//         past: newPast,
//         present: previous,
//         future: [present, ...future]
//       };
//     });
//   }, []);
//
//   const redo = useCallback(() => {
//     setState(currentState => {
//       const { past, present, future } = currentState;
//       if (future.length === 0) return currentState;
//
//       const next = future[0];
//       const newFuture = future.slice(1, past.length);
//
//       return {
//         past: [...past, present],
//         present: next,
//         future: newFuture
//       };
//     });
//   }, []);
//
//   const set = useCallback((newPresent: T) => {
//     setState(currentState => {
//       const { past, present } = currentState;
//       if (newPresent === present) return currentState;
//       return {
//         past: [...past, newPresent],
//         present: newPresent,
//         future: []
//       };
//     });
//   }, []);
//
//   const reset = useCallback((newPresent: T) => {
//     setState(() => {
//       return {
//         past: [],
//         present: newPresent,
//         future: []
//       };
//     });
//   }, []);
//
//   return {
//     undo,
//     redo,
//     set,
//     reset,
//     canUndo,
//     canRedo
//   };
// };
